import fs from 'fs/promises';
import path from 'path';
import { createReadStream, createWriteStream } from 'fs';
import { pipeline } from 'stream/promises';
import JSZip from 'jszip';

// 文件操作工具类
export class FileUtils {
  // 确保目录存在
  static async ensureDirectory(dirPath: string): Promise<void> {
    try {
      await fs.access(dirPath);
    } catch (error) {
      await fs.mkdir(dirPath, { recursive: true });
    }
  }

  // 检查文件是否存在
  static async fileExists(filePath: string): Promise<boolean> {
    try {
      await fs.access(filePath);
      return true;
    } catch {
      return false;
    }
  }

  // 获取文件信息
  static async getFileInfo(filePath: string): Promise<{
    size: number;
    createdAt: Date;
    modifiedAt: Date;
    isDirectory: boolean;
    extension: string;
  }> {
    const stats = await fs.stat(filePath);
    const extension = path.extname(filePath).toLowerCase();

    return {
      size: stats.size,
      createdAt: stats.birthtime,
      modifiedAt: stats.mtime,
      isDirectory: stats.isDirectory(),
      extension
    };
  }

  // 读取文件内容
  static async readFile(filePath: string, encoding: BufferEncoding = 'utf8'): Promise<string> {
    return fs.readFile(filePath, encoding);
  }

  // 写入文件内容
  static async writeFile(filePath: string, content: string | Buffer): Promise<void> {
    const dir = path.dirname(filePath);
    await this.ensureDirectory(dir);
    await fs.writeFile(filePath, content);
  }

  // 追加文件内容
  static async appendFile(filePath: string, content: string): Promise<void> {
    const dir = path.dirname(filePath);
    await this.ensureDirectory(dir);
    await fs.appendFile(filePath, content);
  }

  // 复制文件
  static async copyFile(sourcePath: string, destPath: string): Promise<void> {
    const dir = path.dirname(destPath);
    await this.ensureDirectory(dir);
    await fs.copyFile(sourcePath, destPath);
  }

  // 移动文件
  static async moveFile(sourcePath: string, destPath: string): Promise<void> {
    const dir = path.dirname(destPath);
    await this.ensureDirectory(dir);
    await fs.rename(sourcePath, destPath);
  }

  // 删除文件
  static async deleteFile(filePath: string): Promise<void> {
    try {
      await fs.unlink(filePath);
    } catch (error: any) {
      if (error.code !== 'ENOENT') {
        throw error;
      }
    }
  }

  // 删除目录及其内容
  static async deleteDirectory(dirPath: string): Promise<void> {
    try {
      await fs.rm(dirPath, { recursive: true, force: true });
    } catch (error: any) {
      if (error.code !== 'ENOENT') {
        throw error;
      }
    }
  }

  // 列出目录内容
  static async listDirectory(dirPath: string): Promise<Array<{
    name: string;
    path: string;
    isDirectory: boolean;
    size: number;
    modifiedAt: Date;
  }>> {
    const entries = await fs.readdir(dirPath);
    const results = [];

    for (const entry of entries) {
      const fullPath = path.join(dirPath, entry);
      const stats = await fs.stat(fullPath);

      results.push({
        name: entry,
        path: fullPath,
        isDirectory: stats.isDirectory(),
        size: stats.size,
        modifiedAt: stats.mtime
      });
    }

    return results;
  }

  // 获取目录大小
  static async getDirectorySize(dirPath: string): Promise<number> {
    let totalSize = 0;
    const entries = await this.listDirectory(dirPath);

    for (const entry of entries) {
      if (entry.isDirectory) {
        totalSize += await this.getDirectorySize(entry.path);
      } else {
        totalSize += entry.size;
      }
    }

    return totalSize;
  }

  // 清理临时文件
  static async cleanupTempFiles(tempDir: string, maxAgeHours: number = 24): Promise<number> {
    const cutoffTime = Date.now() - (maxAgeHours * 60 * 60 * 1000);
    let deletedCount = 0;

    try {
      const entries = await this.listDirectory(tempDir);

      for (const entry of entries) {
        if (entry.modifiedAt.getTime() < cutoffTime) {
          if (entry.isDirectory) {
            await this.deleteDirectory(entry.path);
          } else {
            await this.deleteFile(entry.path);
          }
          deletedCount++;
        }
      }
    } catch (error) {
      // 忽略目录不存在的错误
    }

    return deletedCount;
  }

  // 生成唯一文件名
  static generateUniqueFileName(originalName: string, directory: string): string {
    const ext = path.extname(originalName);
    const baseName = path.basename(originalName, ext);
    const timestamp = Date.now();
    const random = Math.random().toString(36).substring(2, 8);
    
    return path.join(directory, `${baseName}_${timestamp}_${random}${ext}`);
  }

  // 验证文件路径安全性
  static validateFilePath(filePath: string, allowedDirectory: string): boolean {
    const resolvedPath = path.resolve(filePath);
    const resolvedAllowedDir = path.resolve(allowedDirectory);
    
    return resolvedPath.startsWith(resolvedAllowedDir);
  }

  // 获取文件MIME类型
  static getMimeType(filePath: string): string {
    const ext = path.extname(filePath).toLowerCase();
    const mimeTypes: Record<string, string> = {
      '.sql': 'application/sql',
      '.txt': 'text/plain',
      '.json': 'application/json',
      '.csv': 'text/csv',
      '.xlsx': 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
      '.xls': 'application/vnd.ms-excel',
      '.zip': 'application/zip',
      '.pdf': 'application/pdf',
      '.log': 'text/plain'
    };

    return mimeTypes[ext] || 'application/octet-stream';
  }

  // 创建ZIP文件
  static async createZipFile(files: Array<{ name: string; content: string | Buffer }>, outputPath: string): Promise<void> {
    const zip = new JSZip();

    for (const file of files) {
      zip.file(file.name, file.content);
    }

    const zipBuffer = await zip.generateAsync({ type: 'nodebuffer' });
    await this.writeFile(outputPath, zipBuffer);
  }

  // 解压ZIP文件
  static async extractZipFile(zipPath: string, extractDir: string): Promise<string[]> {
    const zipBuffer = await fs.readFile(zipPath);
    const zip = await JSZip.loadAsync(zipBuffer);
    const extractedFiles: string[] = [];

    await this.ensureDirectory(extractDir);

    for (const [relativePath, zipEntry] of Object.entries(zip.files)) {
      if (!zipEntry.dir) {
        const content = await zipEntry.async('nodebuffer');
        const fullPath = path.join(extractDir, relativePath);
        
        // 确保目标目录存在
        await this.ensureDirectory(path.dirname(fullPath));
        
        await this.writeFile(fullPath, content);
        extractedFiles.push(fullPath);
      }
    }

    return extractedFiles;
  }

  // 流式复制文件（适用于大文件）
  static async streamCopyFile(sourcePath: string, destPath: string): Promise<void> {
    const dir = path.dirname(destPath);
    await this.ensureDirectory(dir);

    const readStream = createReadStream(sourcePath);
    const writeStream = createWriteStream(destPath);

    await pipeline(readStream, writeStream);
  }

  // 计算文件哈希
  static async calculateFileHash(filePath: string, algorithm: string = 'sha256'): Promise<string> {
    const crypto = await import('crypto');
    const hash = crypto.createHash(algorithm);
    const stream = createReadStream(filePath);

    return new Promise((resolve, reject) => {
      stream.on('data', (data) => hash.update(data));
      stream.on('end', () => resolve(hash.digest('hex')));
      stream.on('error', reject);
    });
  }

  // 格式化文件大小
  static formatFileSize(bytes: number): string {
    if (bytes === 0) return '0 Bytes';

    const k = 1024;
    const sizes = ['Bytes', 'KB', 'MB', 'GB', 'TB'];
    const i = Math.floor(Math.log(bytes) / Math.log(k));

    return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + ' ' + sizes[i];
  }

  // 获取文件扩展名
  static getFileExtension(fileName: string): string {
    return path.extname(fileName).toLowerCase().substring(1);
  }

  // 清理文件名（移除非法字符）
  static sanitizeFileName(fileName: string): string {
    return fileName
      .replace(/[<>:"/\\|?*]/g, '_') // 替换非法字符
      .replace(/\s+/g, '_') // 替换空格
      .replace(/_{2,}/g, '_') // 合并多个下划线
      .replace(/^_|_$/g, ''); // 移除开头和结尾的下划线
  }

  // 创建备份文件
  static async createBackup(filePath: string, backupDir: string): Promise<string> {
    const fileName = path.basename(filePath);
    const timestamp = new Date().toISOString().replace(/[:.]/g, '-');
    const backupFileName = `${timestamp}_${fileName}`;
    const backupPath = path.join(backupDir, backupFileName);

    await this.ensureDirectory(backupDir);
    await this.copyFile(filePath, backupPath);

    return backupPath;
  }

  // 旋转日志文件
  static async rotateLogFile(logPath: string, maxFiles: number = 5): Promise<void> {
    if (!(await this.fileExists(logPath))) {
      return;
    }

    const dir = path.dirname(logPath);
    const ext = path.extname(logPath);
    const baseName = path.basename(logPath, ext);

    // 移动现有的编号文件
    for (let i = maxFiles - 1; i >= 1; i--) {
      const currentFile = path.join(dir, `${baseName}.${i}${ext}`);
      const nextFile = path.join(dir, `${baseName}.${i + 1}${ext}`);

      if (await this.fileExists(currentFile)) {
        if (i === maxFiles - 1) {
          await this.deleteFile(currentFile);
        } else {
          await this.moveFile(currentFile, nextFile);
        }
      }
    }

    // 移动当前日志文件
    const firstRotatedFile = path.join(dir, `${baseName}.1${ext}`);
    await this.moveFile(logPath, firstRotatedFile);
  }

  // 监控目录变化
  static watchDirectory(dirPath: string, callback: (eventType: string, filename: string) => void): () => void {
    const fs = require('fs');
    const watcher = fs.watch(dirPath, { recursive: true }, callback);
    
    return () => watcher.close();
  }

  // 获取相对路径
  static getRelativePath(from: string, to: string): string {
    return path.relative(from, to);
  }

  // 规范化路径
  static normalizePath(filePath: string): string {
    return path.normalize(filePath);
  }

  // 检查路径是否为绝对路径
  static isAbsolutePath(filePath: string): boolean {
    return path.isAbsolute(filePath);
  }
}